package vn.edu.hut.soict.translate;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import vn.edu.hut.soict.translate.search.Record;
import vn.edu.hut.soict.translate.search.SearchState;
import vn.edu.hut.soict.translate.search.SentenceSearcher;
import vn.edu.hut.soict.translate.transform.InnerTransformer;
import vn.edu.hut.soict.translate.wordgraph.Word;
import vn.edu.hut.soict.translate.wordgraph.WordGraph;
import vn.edu.hut.soict.translate.wordgraph.WordGraphReader;

public class Translator {
	private static final double THRESHOLD = 1;
	private SentenceSplitter splitter;
	private SentenceSearcher searcher;
	private InnerTransformer transformer;
	private WordGraph[][] graphs;

	private int bestECount, bestSCount, bestICount;
	private int eCount, sCount, iCount;

	public Translator() {
		this(WordGraph.GRAPH_FILE);
	}

	public Translator(String graphFile) {
		splitter = new DefaultSentenceSplitter();
		transformer = new InnerTransformer();
		graphs = (new WordGraphReader().read(graphFile));
	}

	public Translator(WordGraph[][] graphs) {
		splitter = new DefaultSentenceSplitter();
		transformer = new InnerTransformer();
		this.graphs = graphs;
	}

	private List<WordGraph> findCandidate(Word[] sentence) {
		List<WordGraph> candidates = new ArrayList<WordGraph>();
		int contentWord = 0;
		int functionalWord = 0;

		for (int i = 0; i < sentence.length; i++) {
			if (sentence[i].isContentWord()) {
				contentWord++;
			}
			else {
				functionalWord++;
			}
		}

		for (int i = 0; i < graphs.length; i++) {
			for (int j = 0; j < graphs[i].length; j++) {
				double limit = (1 - THRESHOLD) / (1 + THRESHOLD);
				double ratio = ((double) (i + j)) / (contentWord + functionalWord);
				if (limit < ratio && ratio < 1 / limit) {
					WordGraph graph = graphs[i][j];
					if (graph != null) {
						candidates.add(graph);
					}
				}
			}
		}
		return candidates;
	}

	private List<Record> bestResult(List<SearchState> results) {
		List<Record> best = null;

		if (results == null || results.size() == 0) {
			return null;
		}

		best = results.get(0).getPaths().get(0);
		for (SearchState s : results) {
			for (List<Record> path : s.getPaths()) {
				countBestRecordType(best);
				countRecordType(path);
				if (eCount > bestECount) {
					best = path;
				}
				else if (eCount == bestECount) {
					if (sCount > bestSCount) {
						best = path;
					}
					else if (sCount == bestSCount) {
						if (iCount < bestICount) {
							best = path;
						}
					}
				}
			}
		}

		return best;
	}

	private void countRecordType(List<Record> path) {
		eCount = 0;
		sCount = 0;
		iCount = 0;
		for (Record record : path) {
			switch (record.getOperator()) {
				case EXACT_MATCH:
					eCount++;
					break;
				case SUBSTITUTION:
					sCount++;
					break;
				case INSERTION:
					iCount++;
					break;
			}
		}
	}

	private void countBestRecordType(List<Record> path) {
		bestECount = 0;
		bestSCount = 0;
		bestICount = 0;
		for (Record record : path) {
			switch (record.getOperator()) {
				case EXACT_MATCH:
					bestECount++;
					break;
				case SUBSTITUTION:
					bestSCount++;
					break;
				case INSERTION:
					bestICount++;
					break;
			}
		}
	}

	public String translate(String s) {
		Word[] sentence = splitter.split(s);
		return translate(sentence);
	}

	public void translate(BufferedReader reader, BufferedWriter writer) {
		try {
			String sentence = reader.readLine();
			while (sentence != null) {
				String translation = translate(sentence);
				if (translation == null) {
					writer.write("Không dịch được.\r\n");
				}
				else {
					writer.write(translation);
					writer.write("\r\n");
				}
				sentence = reader.readLine();
			}
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		finally {
			try {
				if (reader != null) {
					reader.close();
				}
				if (writer != null) {
					writer.close();
				}
			}
			catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public String translate(Word[] sentence) {
		searcher = new SentenceSearcher(THRESHOLD);
		List<SearchState> results = new ArrayList<SearchState>();

		List<WordGraph> candidates = findCandidate(sentence);
		for (WordGraph graph : candidates) {
			List<SearchState> newResult = searcher.matchingSequences(graph, sentence);
			if (results != null && results.size() > 0 && newResult != null && newResult.size() > 0) {
				if (results.get(0).getCost() > newResult.get(0).getCost()) {
					results.removeAll(results);
				}
			}
			results.addAll(newResult);
		}

		List<Record> bestResult = bestResult(results);

		return transformer.transform(bestResult);
	}

	public String getVietnameseSentence() {
		return transformer.getVietnameseSentence();
	}

	public String getEnglishSentence() {
		return transformer.getEnglishSentence();
	}

	public static void main(String[] args) {
		if (args.length != 2) {
			System.out.println("Usage: translator input output");
			return;
		}
		Translator translator = new Translator();
		BufferedReader reader = null;
		BufferedWriter writer = null;

		try {
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), "utf-8"));
			writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(args[1]), "utf-8"));
			translator.translate(reader, writer);
		}
		catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
